Observatorio de Medicina Complementaria (2019-2024)
  • Inicio
  • Atenciones Individuales (MINSA)
  • Actividades Grupales (MINSA)
  • Actividades Individuales (SALUDPOL)
  • Oferta de servicios

On this page

  • Oferta: Ministerio de Salud
    • 1. Tipo de Establecimiento de Salud
    • 2. Categoría del Establecimiento de Salud
    • 3. Establecimientos que más reportan
    • 4. Distribución Geográfica de Establecimientos Ofertantes
  • Oferta: Fondo de Aseguramiento Policial-SALUDPOL
  • Oferta: Seguro Social de Salud
    • Clasificación por Tipo
  • Oferta: Establecimientos de Salud Privados (RENIPRESS)

Oferta de servicios de Medicina Complementaria (2019-2024)

Análisis de datos del Ministerio de Salud (MINSA), Seguro Social de Salud (EsSalud), SaludPOL y Superintendencia de Salud (SUSALUD)

Author

Subdirección de Medicina Complementaria (SUMEC-CENSI)

Published

December 11, 2025

Oferta: Ministerio de Salud

Establecimientos de Salud (MINSA)

2,695

Producción HIS registrada

Centros y Unidades de Medicina Complementaria (EsSalud)

74

Reportes Seguro Social de Salud

1. Tipo de Establecimiento de Salud

  • Gráfico
  • Tabla
Code
# Agrupar
resumen_tipo <- df_geo_completo %>%
  filter(Tipo != "NO DEFINIDO") %>%
  count(Tipo, name = "Atenciones") %>% # 'name' define el nombre de la columna conteo
  arrange(desc(Atenciones))

# Gráfico
plot_ly(resumen_tipo, 
        x = ~Atenciones, 
        y = ~reorder(Tipo, Atenciones), 
        type = 'bar', 
        orientation = 'h',
        marker = list(color = '#2980b9')) %>%
  layout(title = "Atenciones según Tipo de Establecimiento",
         xaxis = list(title = "Nro. Atenciones"), yaxis = list(title = ""))
Code
make_download_table(resumen_tipo, filename_label = "atenciones_por_tipo_eess")

2. Categoría del Establecimiento de Salud

  • Gráfico
  • Tabla
Code
resumen_cat <- df_geo_completo %>%
  filter(Categoria != "SIN CATEGORIA") %>%
  count(Categoria, name = "Atenciones") %>%
  arrange(desc(Atenciones))

plot_ly(resumen_cat, 
        x = ~Atenciones, 
        y = ~reorder(Categoria, Atenciones), 
        type = 'bar', 
        orientation = 'h',
        marker = list(color = '#16a085')) %>%
  layout(title = "Atenciones según Categoría del EESS",
         xaxis = list(title = "Nro. Atenciones"), yaxis = list(title = ""))
Code
make_download_table(resumen_cat, filename_label = "atenciones_por_categoria_eess")

3. Establecimientos que más reportan

  • Gráfico
  • Tabla
Code
resumen_top20 <- df_geo_completo %>%
  filter(Nombre_Establecimiento != "DESCONOCIDO") %>%
  group_by(Nombre_Establecimiento, Departamento) %>% # Incluyo Dept para contexto
  summarise(Atenciones = n(), .groups = 'drop') %>%
  arrange(desc(Atenciones)) %>%
  head(20)

plot_ly(resumen_top20, 
        x = ~Atenciones, 
        y = ~reorder(Nombre_Establecimiento, Atenciones), 
        type = 'bar', 
        orientation = 'h',
        text = ~paste(Departamento), # Muestra la región al pasar el mouse
        marker = list(color = '#8e44ad')) %>%
  layout(title = "Top 20 Establecimientos con Mayor Producción",
         xaxis = list(title = "Nro. Atenciones"), 
         yaxis = list(title = ""),
         margin = list(l = 180)) # Margen izquierdo amplio para nombres largos
Code
make_download_table(resumen_top20, filename_label = "top20_establecimientos_atenciones")

4. Distribución Geográfica de Establecimientos Ofertantes

  • Gráfico
  • Tabla
Code
library(leaflet)
library(sf)
library(geodata)
library(dplyr)

# 1. PREPARACIÓN DE DATOS (Dos partes)

# A. Calcular el "Campeón" por Región (El que más produce)
top_productor_region <- df_geo_completo %>%
  # Filtramos basura
  filter(Tipo != "NO DEFINIDO", Departamento != "SIN INFORMACIÓN") %>%
  # Normalizamos nombres de departamento
  mutate(
    Departamento_Norm = case_when(
      Departamento %in% c("LIMA", "LIMA METROPOLITANA", "LIMA REGIÓN") ~ "LIMA",
      Departamento == "CALLAO" ~ "CALLAO",
      TRUE ~ Departamento
    )
  ) %>%
  # Contamos atenciones por EESS
  group_by(Departamento_Norm, Nombre_Establecimiento) %>%
  summarise(Atenciones_EESS = n(), .groups = 'drop_last') %>%
  # Seleccionamos el #1 de cada región
  slice_max(Atenciones_EESS, n = 1, with_ties = FALSE) %>%
  rename(Top_EESS_Nombre = Nombre_Establecimiento, Top_EESS_Valor = Atenciones_EESS)

# B. Calcular el Total de EESS por Región (La unidad de análisis principal)
data_mapa_oferta <- df_geo_completo %>%
  filter(Tipo != "NO DEFINIDO", Departamento != "SIN INFORMACIÓN") %>%
  mutate(
    Departamento_Norm = case_when(
      Departamento %in% c("LIMA", "LIMA METROPOLITANA", "LIMA REGIÓN") ~ "LIMA",
      Departamento == "CALLAO" ~ "CALLAO",
      TRUE ~ Departamento
    )
  ) %>%
  group_by(Departamento_Norm) %>%
  summarise(
    Total_RENAES = n_distinct(renaes) # <--- AQUÍ CAMBIAMOS LA UNIDAD DE ANÁLISIS
  ) %>%
  # C. Unimos con el dato del "Campeón"
  left_join(top_productor_region, by = "Departamento_Norm")


# 2. OBTENER GEOMETRÍA (GADM)
mapa_peru_gadm <- gadm(country = "PER", level = 1, path = tempdir()) %>% st_as_sf()

# 3. UNIR DATOS CON EL MAPA
mapa_oferta_final <- mapa_peru_gadm %>%
  mutate(NAME_UPPER = toupper(NAME_1)) %>%
  left_join(data_mapa_oferta, by = c("NAME_UPPER" = "Departamento_Norm"))

# 4. PALETA (Verde: Asociado a Infraestructura/Recursos)
paleta_oferta <- colorBin(
  palette = "Greens", 
  domain = mapa_oferta_final$Total_RENAES,
  bins = 5,
  na.color = "#ecf0f1"
)

# 5. GENERAR MAPA LEAFLET
leaflet(mapa_oferta_final) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -75, lat = -9, zoom = 5) %>%
  
  addPolygons(
    fillColor = ~paleta_oferta(Total_RENAES),
    weight = 1, opacity = 1, color = "white", dashArray = "3", fillOpacity = 0.7,
    
    # Efecto Highlight
    highlightOptions = highlightOptions(weight = 3, color = "#2c3e50", bringToFront = TRUE),
    
    # ETIQUETA SIMPLE (Al pasar rápido el mouse)
    label = ~paste0(NAME_1, ": ", Total_RENAES, " Estab."),
    
    # POPUP DETALLADO (Al hacer clic o esperar)
    popup = ~paste0(
      "<div style='font-family: sans-serif;'>",
      "<h4 style='margin-bottom:5px; color:#27ae60;'>", NAME_1, "</h4>",
      "<b>Oferta Disponible:</b> ", Total_RENAES, " Establecimientos<br><hr>",
      "<span style='font-size:0.9em; color:#7f8c8d;'>Mayor Productor:</span><br>",
      "<b>", Top_EESS_Nombre, "</b><br>",
      "(", format(Top_EESS_Valor, big.mark=","), " atenciones)",
      "</div>"
    )
  ) %>%
  
  addLegend(
    pal = paleta_oferta, 
    values = ~Total_RENAES, 
    opacity = 0.7, 
    title = "Nro. EESS",
    position = "bottomright"
  )
Code
# Tabla para descarga
data_export_oferta <- data_mapa_oferta %>%
  rename(Departamento = Departamento_Norm, 
         Cantidad_EESS = Total_RENAES,
         EESS_Mas_Productivo = Top_EESS_Nombre,
         Produccion_Maxima = Top_EESS_Valor) %>%
  arrange(desc(Cantidad_EESS))

make_download_table(data_export_oferta, "Oferta_Regional_EESS")

Oferta: Fondo de Aseguramiento Policial-SALUDPOL

  • Gráfico

Mapa de Oferta SALUDPOL

Oferta: Seguro Social de Salud

Análisis de la infraestructura de Medicina Complementaria en el Seguro Social de Salud (EsSalud).

Clasificación por Tipo

  • Gráfico
  • Tabla
Code
# 1. Conteo simple
conteo_tipos <- df_essalud %>%
  count(Tipo, name = "Cantidad") %>%
  arrange(desc(Cantidad))

# 2. Gráfico
plot_ly(conteo_tipos, 
        x = ~Cantidad, 
        y = ~reorder(Tipo, Cantidad), 
        type = 'bar', 
        orientation = 'h',
        text = ~Cantidad,
        textposition = 'auto',
        marker = list(color = '#0056b3')) %>% # Azul EsSalud Institucional
  layout(
    title = "Distribución de EESS EsSalud por Nivel de Complejidad",
    xaxis = list(title = "Número de Establecimientos"),
    yaxis = list(title = ""),
    margin = list(l = 250) # Margen amplio para nombres largos (CAMec, UMEC...)
  )
Code
make_download_table(conteo_tipos, filename_label = "essalud_eess_por_tipo")
  • Gráfico
  • Tabla
Code
# 1. OBTENER GEOMETRÍA
# Usamos tryCatch para descargar solo si no existe
if(!exists("mapa_peru_gadm")) {
  mapa_peru_gadm <- gadm(country = "PER", level = 1, path = tempdir()) %>% st_as_sf()
}

# 2. UNIR DATOS
# Limpiamos también los nombres del MAPA para que el cruce sea perfecto
mapa_essalud_final <- mapa_peru_gadm %>%
  mutate(
    # Convertir nombres del mapa a mayúsculas y quitar tildes
    NAME_UPPER = toupper(NAME_1),
    NAME_CLEAN = chartr("ÁÉÍÓÚ", "AEIOU", NAME_UPPER)
  ) %>%
  # Cruce usando la columna limpia
  left_join(resumen_essalud_mapa, by = c("NAME_CLEAN" = "Region_Mapa")) %>%
  mutate(
    Total_EESS = replace_na(Total_EESS, 0),
    Desglose_Tipos = replace_na(Desglose_Tipos, "Sin oferta reportada")
  )

# 3. PALETA
paleta_essalud <- colorBin("Blues", domain = mapa_essalud_final$Total_EESS, bins = 5, na.color = "#ecf0f1")

# 4. MAPA
leaflet(mapa_essalud_final) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -75, lat = -9, zoom = 5) %>%
  addPolygons(
    fillColor = ~paleta_essalud(Total_EESS),
    weight = 1, opacity = 1, color = "white", dashArray = "3", fillOpacity = 0.7,
    highlightOptions = highlightOptions(weight = 3, color = "#666", bringToFront = TRUE),
    label = ~paste0(NAME_1, ": ", Total_EESS),
    popup = ~paste0(
      "<div style='font-family: sans-serif;'>",
      "<h4 style='color:#0056b3; margin-bottom:5px;'>", NAME_1, "</h4>",
      "<b>Total Establecimientos:</b> ", Total_EESS, "<hr>",
      "<i>Distribución:</i><br>",
      Desglose_Tipos,
      "</div>"
    )
  ) %>%
  addLegend(pal = paleta_essalud, values = ~Total_EESS, title = "Nro. EESS", position = "bottomright")
Code
# Tabla para descarga
data_export_essalud <- mapa_essalud_final %>%
  st_set_geometry(NULL) %>%
  select(Región = NAME_1, 
         Cantidad_EESS = Total_EESS,
         Desglose_Tipos) %>%
  arrange(desc(Cantidad_EESS))  
make_download_table(data_export_essalud, "Oferta_Regional_EESS_Essalud")

Oferta: Establecimientos de Salud Privados (RENIPRESS)

  • Gráfico
  • Tabla
Code
#| label: mapa-renaes-privados
#| warning: false
#| message: false

# 1. CARGA DE DATOS
# Leemos el archivo y seleccionamos las columnas que se ven en la imagen
df_privados <- read_excel("renaes privados.xls") %>%
  select(
    Codigo_Unico = `Código Único`,
    Nombre_EESS = `Nombre del establecimiento`,
    Departamento,
    Provincia,
    Distrito,
    Ubigeo = UBIGEO
  ) %>%
  mutate(
    # PASO DE LIMPIEZA (Igual al anterior para asegurar cruce)
    Dep_Upper = toupper(Departamento),
    
    Region_Mapa = case_when(
      # Casos especiales de escritura
      Dep_Upper == "LIMA" ~ "LIMA",
      Dep_Upper == "CALLAO" ~ "CALLAO",
      
      # Limpieza general de tildes (ÁNCASH -> ANCASH, JUNÍN -> JUNIN)
      TRUE ~ chartr("ÁÉÍÓÚ", "AEIOU", Dep_Upper)
    )
  )

# 2. PREPARAR RESUMEN PARA EL MAPA
# Contamos cuántos establecimientos privados hay por región
resumen_privados_mapa <- df_privados %>%
  group_by(Region_Mapa) %>%
  summarise(
    Total_Privados = n(),
    .groups = 'drop'
  )

# 1. OBTENER GEOMETRÍA
if(!exists("mapa_peru_gadm")) {
  mapa_peru_gadm <- gadm(country = "PER", level = 1, path = tempdir()) %>% st_as_sf()
}

# 2. UNIR DATOS
mapa_privados_final <- mapa_peru_gadm %>%
  mutate(
    NAME_CLEAN = chartr("ÁÉÍÓÚ", "AEIOU", toupper(NAME_1))
  ) %>%
  left_join(resumen_privados_mapa, by = c("NAME_CLEAN" = "Region_Mapa")) %>%
  mutate(
    Total_Privados = replace_na(Total_Privados, 0)
  )

# 3. PALETA (Usamos naranjas para diferenciar de MINSA/EsSalud)
paleta_privados <- colorBin("Oranges", domain = mapa_privados_final$Total_Privados, bins = 5, na.color = "#ecf0f1")

# 4. MAPA INTERACTIVO
leaflet(mapa_privados_final) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -75, lat = -9, zoom = 5) %>%
  addPolygons(
    fillColor = ~paleta_privados(Total_Privados),
    weight = 1, opacity = 1, color = "white", dashArray = "3", fillOpacity = 0.7,
    highlightOptions = highlightOptions(weight = 3, color = "#666", bringToFront = TRUE),
    
    label = ~paste0(NAME_1, ": ", Total_Privados),
    
    popup = ~paste0(
      "<div style='font-family: sans-serif; text-align: center;'>",
      "<h4 style='color:#d35400; margin-bottom:5px;'>", NAME_1, "</h4>",
      "<b>Oferta Privada:</b><br>", 
      "<span style='font-size: 1.5em; font-weight: bold;'>", format(Total_Privados, big.mark=","), "</span>",
      "<br>Establecimientos",
      "</div>"
    )
  ) %>%
  addLegend(pal = paleta_privados, values = ~Total_Privados, title = "Nro. EESS Privados", position = "bottomright")
Code
# Mostramos la tabla limpia
datatable(df_privados %>% select(-Region_Mapa, -Dep_Upper), # Ocultamos columnas de cálculo
          extensions = 'Buttons',
          options = list(
            dom = 'Bfrtip',
            buttons = c('copy', 'excel', 'csv'),
            pageLength = 10,
            autoWidth = TRUE,
            language = list(url = '//cdn.datatables.net/plug-ins/1.10.11/i18n/Spanish.json')
          ),
          rownames = FALSE,
          class = 'cell-border stripe'
)